﻿#include "GTeamManager.h"
#include "Character/Player.h"
#include "Character/PlayerMgr.h"
#include "LogicService.h"
#include "Common/TeamDefine.h"
#include "Character/monster/Monster.h"
#include "Common/TableData/FriendshipFriendshipCfg.h"
#include "Duplicate/DuplicateMgr.h"
#include "Scene/Scene.h"
#include "Common/ComTypeDefine.h"
#include "Common/AttrMgr/AttrMgr.h"
#include "ServerModule/LogicActivityModule.h"

using namespace ProtoBuf;

GTeamManager::GTeamManager()
{

}

GTeamManager::~GTeamManager()
{

}

bool GTeamManager::Init()
{
	IMessageDispatch *pMessageDispatch = g_GetLogicService()->GetServiceMessageDispatch();
	if (nullptr == pMessageDispatch)
	{
		return false;
	}
	pMessageDispatch->registerServerHandler(EMODULE_ID_TEAM, this);

	g_GetEvent()->Subscribe(dynamic_cast<IEventExecuteSink*>(this), EVENT_CREATURE_DEAD, 0, CREATURE_MONSTER, NULL);

	return true;
}

void GTeamManager::UnInit()
{
	IMessageDispatch *pMessageDispatch = g_GetLogicService()->GetServiceMessageDispatch();
	if (nullptr == pMessageDispatch)
	{
		return;
	}
	pMessageDispatch->unregisterServerHandler(EMODULE_ID_TEAM);

	g_GetEvent()->UnSubscribeAll(this);
}

void GTeamManager::onServerMessage(uint32_t actionId, RECV_PACKAGE &package)
{
	switch (actionId)
	{
	case CENTER_TO_LOGIC_UPDATE_TEAM_NOTIFY:
	{
		OnUpdateTeamNotify(package);
		break;
	}
	case CENTER_TO_LOGIC_LEADER_POS_INFO:
	{
		OnLeaderPosInfo(package);
		break;
	}
	case CENTER_TO_LOGIC_CLOSENESS_LEVEL_NOTIFY:
	{
		OnUpdateTeamClosenessNotify(package);
		break;
	}
	case CENTER_TO_LOGIC_STAR_SOUL_SEND:
	{
		OnStarSoulSend(package);
		break;
	}
	case CENTER_TO_LOGIC_CALL_TEAM_MEMBERS:
	{
		OnWLCallMemsRsp(package);
		break;
	}
	default:
		break;
	}
}

void GTeamManager::OnExecute(uint16_t nEventID, uint64_t nSrcID, uint8_t bySrcType, void *pContext, int32_t nLen)
{
	switch (nEventID)
	{
	case EVENT_CREATURE_DEAD: //生物死亡
	{
		DieEvent dieEvent = *(DieEvent*)pContext;
		uint32_t monsterId = dieEvent.monsterId;
		Player* pPlayer = g_GetCreatureMgr()->GetPlayer(dieEvent.killerCid);
		if (nullptr == pPlayer)
		{
			break;
		}

		//不是组队击杀的不用累计亲密度
		if (pPlayer->GetAttr(C_TEAM_ID) <= 0)
		{
			break;
		}

		if (monsterId > 0 && dieEvent.nCfgType == ENUM_MONSTER_CFG_TYPE_FIELD) //野外怪物死亡
		{	
			GWTeamAddCloseness req;
			req.set_charid(dieEvent.killerCid);
			req.set_type(RELATION_CLOSENESS_KILL_MONSTER);
			g_GetLogicService()->SendDataToCenter(EMODULE_ID_TEAM, LOGIC_TO_CENTER_TEAM_ADD_CLOSENESS, &req);
		}
		break;
	}
	default:
		break;
	}

}

bool GTeamManager::OnUpdateTeamNotify(RECV_PACKAGE &package)
{
	WGUpdateTeamNotify notify;

	if (!notify.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("[logic] GTeamManager::OnUpdateTeamNotify WGUpdateTeamNotify parse failed...");
		return false;
	}

	CharIDType charId = notify.charid();
	TeamID_t teamId = notify.teamid();
	uint32_t isLeader = notify.isleader();
	uint32_t closenessLv = notify.closenesslv();

	Player* pPlayer = g_GetCreatureMgr()->GetPlayer(charId);
	if (nullptr == pPlayer)
	{
		//MMOLOG_FMT_ERROR("[logic] GMailManager::OnUpdateTeamNotify but Player is nullptr charId:%u", charId);
		return false;
	}
	
	TeamID_t oldTeamId = pPlayer->GetAttr(C_TEAM_ID);
	if (oldTeamId > 0 && teamId <= 0) //旧的队伍ID > 0，当前队伍ID <= 0
	{
		LeaveTeamEvent leaveEvent;
		leaveEvent.cid = charId;
		leaveEvent.teamID = oldTeamId;
		g_GetEvent()->FireExecute(EVENT_LEAVE_TEAM, oldTeamId, CREATURE_PLAYER, (LeaveTeamEvent*)&leaveEvent, sizeof(LeaveTeamEvent));

		//副本离开队伍处理
		g_GetDuplicateMgr()->OnLeaveTeam(charId, pPlayer->GetSceneId());
	}

	pPlayer->SetTeamAttr(teamId, isLeader, false);
	//设置玩家最大亲密度等级
	pPlayer->SetAttr(C_CLOSENESS_LEVEL, closenessLv,true);


	uint32_t pAttack = (teamId > 0) ? GetTeamAttackAdd(closenessLv) : 0;
	pPlayer->SetAttrPACache(g_GetAttrMgr()->GetPlayerFightModlePAttr(enFightAttrModule_Relation, C_MAT), pAttack);
	pPlayer->SetAttrPACache(g_GetAttrMgr()->GetPlayerFightModlePAttr(enFightAttrModule_Relation, C_AP), pAttack);
	pPlayer->SynAttrToClient();

	return true;
}

bool GTeamManager::OnLeaderPosInfo(RECV_PACKAGE &package)
{
	WGLeaderPosInfoReq req;
	GWLeaderPosInfoRsp rsp;

	if (!req.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("[logic] GTeamManager::OnTeamFollowInfo WGTeamFollowInfoReq parse failed...");
		return false;
	}

	CharIDType leaderId = req.leaderid();
	CharIDType charId = req.charid();
	Player* pPlayer = g_GetCreatureMgr()->GetPlayer(leaderId);
	if (nullptr == pPlayer)
	{
		GWLeaderPosInfoError errorNotify;
		errorNotify.set_leaderid(leaderId);
		errorNotify.set_charid(charId);
		g_GetLogicService()->SendDataToCenter(EMODULE_ID_TEAM, LOGIC_TO_CENTER_LEADER_POS_INFO_ERROR, &errorNotify);
		return false;
	}
	if (ACCOUNT_GAME_STATE_SWITCH == pPlayer->GetAccountState())
	{
		LogErrFmtPrint("GTeamManager::OnLeaderPosInfo...ACCOUNT_GAME_STATE_SWITCH == pPlayer->GetAccountState() cid:%lu, leaderId:%lu ", charId, leaderId);
		GWLeaderPosInfoError errorNotify;
		errorNotify.set_leaderid(leaderId);
		errorNotify.set_charid(charId);
		g_GetLogicService()->SendDataToCenter(EMODULE_ID_TEAM, LOGIC_TO_CENTER_LEADER_POS_INFO_ERROR, &errorNotify);
		return false;
	}

	uint32_t mapId = pPlayer->GetMapId();
	Point3<float> pos = pPlayer->GetPos();
	rsp.set_charid(charId);
	rsp.set_sceneid(mapId);
	rsp.set_leaderid(leaderId);
	Vector3PB* pCurpos = new Vector3PB();
	pCurpos->set_x(pos.x);
	pCurpos->set_y(pos.y);
	pCurpos->set_z(pos.z);
	rsp.set_allocated_dstpos(pCurpos);
	g_GetLogicService()->SendDataToCenter(EMODULE_ID_TEAM, LOGIC_TO_CENTER_LEADER_POS_INFO, &rsp);

	return true;
}

bool GTeamManager::OnUpdateTeamClosenessNotify(RECV_PACKAGE &package)
{
	WGTeamClonsenessLvNotify notify;

	if (!notify.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("[logic] GTeamManager::OnUpdateTeamClosenessNotify WGTeamClonsenessLvNotify parse failed...");
		return false;
	}

	CharIDType charId = notify.charid();
	uint32_t closenessLv = notify.closenesslv();

	Player* pPlayer = g_GetCreatureMgr()->GetPlayer(charId);
	if (nullptr == pPlayer)
	{
		return false;
	}

	//设置玩家最大亲密度等级
	pPlayer->SetAttr(C_CLOSENESS_LEVEL, closenessLv, true);

	uint32_t pAttack = (pPlayer->GetAttr(C_TEAM_ID) > 0) ? GetTeamAttackAdd(closenessLv) : 0;
	pPlayer->SetAttrPACache(g_GetAttrMgr()->GetPlayerFightModlePAttr(enFightAttrModule_Relation, C_MAT), pAttack);
	pPlayer->SetAttrPACache(g_GetAttrMgr()->GetPlayerFightModlePAttr(enFightAttrModule_Relation, C_AP), pAttack);
	pPlayer->SynAttrToClient();

	return true;
}

bool GTeamManager::OnStarSoulSend(RECV_PACKAGE &package)
{
	WGStarSoulSend wgSend;
	if (!wgSend.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		MMOLOG_FMT_ERROR("[logic] GTeamManager::OnStarSoulSend WGStarSoulSend parse failed...");
		return false;
	}

	StarSoulSendRsp rsp;
	rsp.set_retcode(RET_SUCCESS);

	CharIDType charId = wgSend.charid();
	Player* pPlayer = g_GetCreatureMgr()->GetPlayer(charId);
	if (nullptr == pPlayer)
	{
		MMOLOG_FMT_ERROR("[logic] GTeamManager::OnStarSoulSend nullptr == pPlayer...charId:%lu", charId);
		return false;
	}

	if (ACCOUNT_GAME_STATE_SWITCH == pPlayer->GetAccountState())
	{
		LogErrFmtPrint("GTeamManager::OnStarSoulSend....ACCOUNT_GAME_STATE_SWITCH == pPlayer->GetAccountState()..cid:%lu, mapid:%u,pos:%f,%f,%f ", charId, wgSend.map_id(), wgSend.cur_pos().x(), wgSend.cur_pos().y(), wgSend.cur_pos().z());
		rsp.set_retcode(RET_FAIL);
		return pPlayer->SendDataToClient(EMODULE_ID_TEAM, LOGIC_TO_CLIENT_STAR_SOUL_RESP, &rsp);
	}
	
	//遗失之城活动期间不能使用
	if (!g_GetGActivityMgr()->CanTransScene(pPlayer))
	{
		rsp.set_retcode(RET_PACKAGE_ITEM_LOST_CITY_FORBID);
		return pPlayer->SendDataToClient(EMODULE_ID_TEAM, LOGIC_TO_CLIENT_STAR_SOUL_RESP, &rsp);
	}

	ERetCode ret = RET_SUCCESS;
	if (!pPlayer->CanTrans(ret, wgSend.map_id(), wgSend.map_id()))
	{
		rsp.set_retcode(ret);
		return pPlayer->SendDataToClient(EMODULE_ID_TEAM, LOGIC_TO_CLIENT_STAR_SOUL_RESP, &rsp);
	}

	//动态地图或副本不能标记
	if (pPlayer->GetScene()->IsDynamic() || nullptr != g_GetDuplicateMgr()->GetDuplicate(pPlayer->GetSceneId()))
	{
		rsp.set_retcode(RET_PACKAGE_MARK_FORDID);
		return pPlayer->SendDataToClient(EMODULE_ID_TEAM, LOGIC_TO_CLIENT_STAR_SOUL_RESP, &rsp);
	}

	//一些静态活动地图不能标记
	/*if (IsForbidUse(m_pMaster->GetSceneId()))
	{
	StarSoulSendRsp rsp;
	rsp.set_retcode(RET_PACKAGE_MARK_FORDID);
	m_pMaster->SendDataToClient(EMODULE_ID_PACKAGE, LOGIC_TO_CLIENT_STAR_SOUL_RESP, &rsp);
	return;
	}*/
	STransParam transParam;
	transParam.srcMapId = pPlayer->GetMapId();
	transParam.transType = ETransType_StarSoul;
	if (wgSend.type() == 2)	//响应队长星魂号角
	{
		transParam.transType = ETransType_StarSoulRsp;

		if (pPlayer->GetAttr(C_TEAM_ID) <= 0)
		{
			rsp.set_retcode(RET_TEAM_NO_EXIST);
			return pPlayer->SendDataToClient(EMODULE_ID_TEAM, LOGIC_TO_CLIENT_STAR_SOUL_RESP, &rsp);
		}

		ProtoBuf::GWChatMsgReq g2wChatMsg;
		g2wChatMsg.set_chattype(CHAT_TYPE_TEAM);
		g2wChatMsg.set_fromid(pPlayer->GetCid());
		ChatContentInfo *content = g2wChatMsg.add_chatcontent();
		char text[256] = { 0 };
		//snprintf(text, sizeof(text), "队员%s已响应队长传送至集合位置", pPlayer->GetName().c_str());
		snprintf(text, sizeof(text), "队员%s已响应队长传送至集合位置", pPlayer->GetName().c_str());
		content->set_describes(text);
		g_GetLogicService()->SendDataToCenter(EMODULE_ID_CHAT, CENTER_SERVER_PROTOCOL_CHAT_REQ, &g2wChatMsg);
	}

	Point3<float> pos;
	pos.x = wgSend.cur_pos().x();
	pos.y = wgSend.cur_pos().y();
	pos.z = wgSend.cur_pos().z();
	pPlayer->TransScene(wgSend.map_id(), pos, wgSend.map_id(), transParam);
	LogDebugFmtPrint("[logic] GTeamManager::OnStarSoulSend....cid:%lu, curscene:%u, curmapid:%u, dstmap:%u, pos:[%f,%f,%f] ", pPlayer->GetCid(), pPlayer->GetSceneId(), pPlayer->GetMapId(), wgSend.map_id(), pos.x, pos.y, pos.z);
	return pPlayer->SendDataToClient(EMODULE_ID_TEAM, LOGIC_TO_CLIENT_STAR_SOUL_RESP, &rsp);
}

bool GTeamManager::OnWLCallMemsRsp(RECV_PACKAGE &package)
{
	WGTeamCallMembers teamCallMembers;
	if (!teamCallMembers.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		LogErrFmtPrint("[logic] GTeamManager::OnWLCallMemsRsp parse failed...");
		return false;
	}

	CharIDType playerID = teamCallMembers.leaderid();
	Player* pPlayer = g_GetCreatureMgr()->GetPlayer(playerID);
	if (nullptr == pPlayer)
	{
		MMOLOG_FMT_ERROR("[logic] GTeamManager::OnWLCallMemsRsp but player is nullptr playerId=%u", playerID);
		return false;
	}

	Part *pPackage = pPlayer->GetPart(PART_PACKAGE);
	if (nullptr == pPackage)
	{
		MMOLOG_FMT_ERROR("[logic] GTeamManager::OnWLCallMemsRsp but pPackage part is nullptr playerId=%u", playerID);
		return false;
	}

	pPackage->OnStarSoulRsp(teamCallMembers.ret(), teamCallMembers.itemidx());
	return true;
}

uint32_t GTeamManager::GetTeamExpAdd(uint32_t closenessLv)
{
	const FriendshipFriendshipCfgInfo* pFriendShipCfg = g_GetFriendshipFriendshipCfgTable()->GetFriendshipFriendshipCfgInfo(closenessLv);
	if (nullptr == pFriendShipCfg)
	{
		return 0;
	}

	return pFriendShipCfg->expBuff;
}

uint32_t GTeamManager::GetTeamAttackAdd(uint32_t closenessLv)
{
	const FriendshipFriendshipCfgInfo* pFriendShipCfg = g_GetFriendshipFriendshipCfgTable()->GetFriendshipFriendshipCfgInfo(closenessLv);
	if (nullptr == pFriendShipCfg)
	{
		return 0;
	}

	return pFriendShipCfg->attackBuff;
}

uint32_t			GTeamManager::GetNearTeamAverageLevel(Creature * pCreature)
{
	uint32_t level = 1;
	uint32_t sumLevel = 0;
	uint32_t sumCount = 0;

	if (!pCreature)
	{
		LogErrFmtPrint("GTeamManager::GetNearTeamAverageLevel pCreature =null");
		return level;
	}

	//先找到该逻辑服的所有玩家
	//找出仇恨列表中有队伍的玩家队伍ID
	std::vector<Creature*> vCreature;
	uint32_t teamID = pCreature->GetAttr(C_TEAM_ID);
	if (teamID > 0)
	{
		Scene * pScene = pCreature->GetScene();
		if (pScene)
		{
			LIST_UINT64 clist;
			pScene->FindCreatureInCircle(clist, pCreature->GetPos(), 60);
			LIST_UINT64::iterator iter = clist.begin();
			for (; iter != clist.end(); ++iter)
			{
				Creature * pCreature = pScene->GetCreature(*iter);
				if (pCreature && pCreature->GetAttr(C_TEAM_ID) == teamID)
				{
					sumLevel += pCreature->GetAttr(C_LEVEL);
					sumCount++;
				}
			}

			if (sumCount>0)
			{
				level = sumLevel / sumCount;
			}
		}
	}
	
	return level;
}

//队员取消跟随
void GTeamManager::CancelFllow(uint32_t teamId,SET_UINT64 setCid)
{
	if (setCid.size() <= 0)
	{
		return;
	}
	ProtoBuf::GWMemberCancelFollow cancelFollow;
	cancelFollow.set_teamid(teamId);
	SET_UINT64::iterator iter = setCid.begin();
	for (; iter != setCid.end(); ++iter)
	{
		cancelFollow.add_charid_lst((*iter));
	}
	g_GetLogicService()->SendDataToCenter(EMODULE_ID_TEAM, LOGIC_TO_CENTER_CANCEL_FOLLOW, &cancelFollow);
}

